
/*
 * @项目名称: 模板开发
 * @FilePath: /meek/src/renderer/render/bezierrender.js
 * @Author: kongxueyang@datatang.com
 * @Date: 2021-01-11T15:38:35+08:00
 * @LastEditors: kongxueyang@datatang.com
 * @LastEditTime: 2021-01-11T15:38:35+08:00
 * Copyright (c) 2018-2022 
 */

import LineStyle from '../../style/linestyle'
import pointrender from './pointrender'
import {colorToString} from '../../utils/helpers'

export class BezierMaker {

  constructor(ctx, bezierCtrlNodesArr, color) {
    this.ctx = ctx;
    this.bezierCtrlNodesArr = bezierCtrlNodesArr ? bezierCtrlNodesArr : [];
    this.color = color ? color : '#ffffff';
    this.bezierArr = [];
  }

  bezier(t) {
    let x = 0,
      y = 0,
      bezierCtrlNodesArr = this.bezierCtrlNodesArr,
      n = bezierCtrlNodesArr.length - 1,
      self = this;
    bezierCtrlNodesArr.forEach(function (item, index) {
      if (!index) {
        x += item.x * Math.pow((1 - t), n - index) * Math.pow(t, index)
        y += item.y * Math.pow((1 - t), n - index) * Math.pow(t, index)
      } else {
        x += self.factorial(n) / self.factorial(index) / self.factorial(n - index) * item.x * Math.pow(
          (1 - t),
          n - index
        ) * Math.pow(t, index)
        y += self.factorial(n) / self.factorial(index) / self.factorial(n - index) * item.y * Math.pow(
          (1 - t),
          n - index
        ) * Math.pow(t, index)
      }
    })
    return { x: x, y: y }
  }

  drawBezier() {
    var nodeArr = this.bezierCtrlNodesArr
    if (nodeArr.length === 2) {
      console.warn('Control nodes should be more then two!')
      var startNode = nodeArr[0],
        endNode = nodeArr[1];
      this.ctx.moveTo(startNode.x, startNode.y);
      this.ctx.lineTo(endNode.x, endNode.y);
      this.ctx.stroke();
    } else if (nodeArr.length === 3) {
      var startNode = nodeArr[0],
        ctrlNode = nodeArr[1],
        endNode = nodeArr[2];
      this.ctx.beginPath()
      this.ctx.moveTo(startNode.x, startNode.y)
      this.ctx.quadraticCurveTo(ctrlNode.x, ctrlNode.y, endNode.x, endNode.y)
      this.ctx.stroke()
    } else if (nodeArr.length === 4) {
      var startNode = nodeArr[0],
        ctrlNodeA = nodeArr[1],
        ctrlNodeB = nodeArr[2],
        endNode = nodeArr[3];
      this.ctx.beginPath()
      this.ctx.moveTo(startNode.x, startNode.y)
      this.ctx.bezierCurveTo(
          ctrlNodeA.x,
          ctrlNodeA.y,
          ctrlNodeB.x,
          ctrlNodeB.y,
          endNode.x,
          endNode.y
        )
      this.ctx.stroke()
    } else {
      var self = this;
      this.bezierArr = [];
      for (let i = 0; i < 1; i += 0.01) {
        this.bezierArr.push(this.bezier(i))
      }
      this.bezierArr.forEach(function (obj, index) {
          if (index) {
            var startX = self.bezierArr[index - 1].x,
              startY = self.bezierArr[index - 1].y,
              x = obj.x,
              y = obj.y;
            self.ctx.beginPath()
            self.ctx.moveTo(startX, startY)
            self.ctx.lineTo(x, y)
            self.ctx.stroke()
          }
        })
    }
  }

  drawBezierPath() {
    var self = this;
    let bezierArr = [];
    let bezierCtrlNodesArr = this.bezierCtrlNodesArr;
    for (let i = 0; i < 1; i += 0.01) {
      bezierArr.push(this.bezier(i))
    }
    const start = bezierCtrlNodesArr[0];
    const end = bezierCtrlNodesArr[bezierCtrlNodesArr.length - 1];
    self.ctx.lineTo(start.x, start.y);
    bezierArr.forEach(function (obj, index) {
        if (index) {
          var startX = bezierArr[index - 1].x,
            startY = bezierArr[index - 1].y,
            x = obj.x,
            y = obj.y;
          self.ctx.lineTo(startX, startY)
          self.ctx.lineTo(x, y)
        }
      })
    self.ctx.lineTo(end.x, end.y);
  }



  factorial(num) {
    if (num <= 1) {
      return 1;
    } else {
      return num * this.factorial(num - 1);
    }
  }
}





export default {
  bezierMaker: new BezierMaker(),
  drawBezier(ctx, renderOpt) {
    ctx.save()
    if (renderOpt.strokeStyle) {
      ctx.strokeStyle = renderOpt.strokeStyle
    }
    if (renderOpt.width) {
      ctx.lineWidth = renderOpt.width
    }
    if (renderOpt.lineCap) {
      ctx.lineCap = renderOpt.lineCap
    }
    if (renderOpt.lineJion) {
      ctx.lineJoin = renderOpt.lineJion
    }
    if (renderOpt.miterLimit) {
      ctx.miterLimit = renderOpt.miterLimit
    }

    ctx.beginPath()


    if (renderOpt.style === LineStyle.DASH) {
      ctx.setLineDash([5, 5])
    } else if (renderOpt.style === LineStyle.DASHDOT) {
      ctx.setLineDash([10, 3, 3, 3]);
    }
    const coordinates = renderOpt.coordinates;
    this.bezierMaker.ctx = ctx;
    this.bezierMaker.bezierCtrlNodesArr = coordinates.map(item => {
      return {
        x: item[0],
        y: item[1]
      }
    });
    this.bezierMaker.drawBezier();

    ctx.stroke()

    ctx.closePath()
    ctx.restore()
  },


  drawPoint(ctx, renderOpt, feature) {

    const renderCoords = renderOpt.coordinates;
    renderCoords.forEach(item => {
      let renderOptions = {
        centerX: item[0] | 0,
        centerY: item[1] | 0,
        radius: feature.readuis,
        // fillStyle: colorToString(styleObj.color),
        fillStyle: '',
        borderStyle: {
          color: [255, 255, 255],
          alpha: 1
        }
      }
      pointrender.prototype.drawCircle(ctx, renderOptions);
    })
  },

  drawBezierPath(ctx, renderOpt) {
    const coordinates = renderOpt.coordinates;
    this.bezierMaker.ctx = ctx;
    this.bezierMaker.bezierCtrlNodesArr = coordinates.map(item => {
      return {
        x: item[0],
        y: item[1]
      }
    });
    this.bezierMaker.drawBezierPath();
  }
}
